/**
 * 增强版通用拷贝函数（支持深拷贝，含 Map, Set, Symbol, 循环引用）
 *  基本类型		   原样返回
    对象/数组		   递归复制
    Date		     创建新 Date 实例
    RegExp		     正确复制 source 和 flags
    Map		         键值对递归拷贝
    Set		         元素递归拷贝
    Symbol		     作为属性键或值均支持
    循环引用		  使用 WeakMap 安全处理
    原型链		      使用 Object.create() 保留
    getter/setter	 使用 Object.defineProperty 复制描述符
 * @param {*} obj - 要拷贝的对象
 * @param {WeakMap} [hash] - 用于处理循环引用的 WeakMap（递归使用）
 * @returns {*} 深拷贝后的新对象
 */
function deepClone(obj, hash = new WeakMap()) {
    // 基本类型、null、undefined、函数 直接返回
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }

    // 处理循环引用
    if (hash.has(obj)) {
        return hash.get(obj);
    }

    let result;

    // 根据对象类型初始化 result
    if (obj instanceof Date) {
        result = new Date(obj);
    } else if (obj instanceof RegExp) {
        result = new RegExp(obj.source, obj.flags); // 更安全地复制正则表达式
    } else if (obj instanceof Map) {
        result = new Map();
        hash.set(obj, result); // 提前缓存，防止循环引用
        for (let [key, value] of obj) {
            result.set(deepClone(key, hash), deepClone(value, hash));
        }
        return result;
    } else if (obj instanceof Set) {
        result = new Set();
        hash.set(obj, result);
        for (let value of obj) {
            result.add(deepClone(value, hash));
        }
        return result;
    } else if (Array.isArray(obj)) {
        result = [];
    } else {
        // 普通对象（包括自定义类实例）
        result = Object.create(Object.getPrototypeOf(obj)); // 保留原型链
    }

    // 缓存当前对象，用于处理循环引用
    hash.set(obj, result);

    // 复制可枚举属性（包括 Symbol 属性）
    const symbols = Object.getOwnPropertySymbols(obj);
    const allKeys = [...Object.keys(obj), ...symbols];

    for (let key of allKeys) {
        const descriptor = Object.getOwnPropertyDescriptor(obj, key);

        if (descriptor && descriptor.enumerable) {
            // 递归拷贝属性值
            result[key] = deepClone(obj[key], hash);
        } else {
            // 非枚举属性，直接复制描述符（如 getter/setter）
            Object.defineProperty(result, key, {
                ...descriptor,
                value: descriptor.value ? deepClone(descriptor.value, hash) : undefined
            });
        }
    }

    return result;
}

// 使用示例

// // 构造一个复杂对象，包含多种类型
// const sym1 = Symbol('id');
// const sym2 = Symbol('meta');

// const original = {
//     name: "Bob",
//     age: 30,
//     tags: ["a", "b"],
//     config: {
//         theme: "dark"
//     },
//     date: new Date(),
//     regex: /test/i,
//     mapData: new Map([
//         ['key1', { x: 1 }],
//         [sym1, 'symbol-as-key']
//     ]),
//     setData: new Set([1, 2, { y: 3 }]),
//     [sym2]: { info: "metadata" },
//     method: function() { console.log(this.name); },
//     get fullName() {
//         return this.name + " Smith";
//     }
// };

// // 构造循环引用
// original.self = original;
// original.mapData.set('selfMap', original);

// // 深拷贝
// const cloned = deepClone(original);

// // 验证拷贝结果
// console.log(cloned.name); // "Bob"
// console.log(cloned.config === original.config); // false ✅ 引用不同
// console.log(cloned.date instanceof Date); // true ✅ 日期被正确复制
// console.log(cloned.regex instanceof RegExp); // true ✅ 正则被正确复制

// // Map 和 Set 拷贝验证
// console.log(cloned.mapData instanceof Map); // true
// console.log(cloned.setData instanceof Set); // true
// console.log(cloned.mapData.get(sym1)); // "symbol-as-key"

// // Symbol 属性验证
// console.log(cloned[sym2].info); // "metadata"

// // 循环引用验证
// console.log(cloned.self === cloned); // true ✅ 正确重建循环引用

// // getter 验证
// console.log(cloned.fullName); // "Bob Smith"

// // 修改拷贝对象不影响原对象
// cloned.config.theme = "light";
// console.log(original.config.theme); // "dark" ✅ 未受影响

export { deepClone }